/**
 *  @file  UdpStream.h version 1.0 2007-11-20
 *  @brief Define wrapper class TemplateUdpStream for UDP socket stream.
 *  Copyright (c) 2007 by @author <abitfree@gmail.com>
 */

#ifndef __UDP_STREAM_H__
#define __UDP_STREAM_H__

#include "AsynSocketHandle.h"
#include "InternetAddress.h"

namespace vs {
namespace net {

/**
@brief Wrapper class for UDP socket stream.
This class can receive/send data via the underlying socket stream.
*/
template<typename SOCK>
class TemplateUdpStream : public SOCK
{
public:
	///@{
	/// Constructors.
	TemplateUdpStream(const InternetAddress &local_address);
	TemplateUdpStream(unsigned short local_port=0, const char *local_addr=0);
	///@}

	///@{
	/// Initializers.
	int Init(const InternetAddress &local_address);
	int Init(unsigned short local_port, const char *local_addr);
	///@}

	/// Send data to peer host.
	int SendTo(const char *buf, int len, int flags, InternetAddress *peer_address);

	/// Receive data from peer host.
	int RecvFrom(char *buf, int len, int flags, InternetAddress *peer_address=0);
};


/// The blocking UDP stream class.
typedef TemplateUdpStream<SocketHandle> UdpStream;

/// The non-blocking UDP stream class.
typedef TemplateUdpStream<AsynSocketHandle> AsynUdpStream;

template<typename SOCK>
INLINE
TemplateUdpStream<SOCK>::TemplateUdpStream(const InternetAddress &local_address)
{
	Init(local_address);
}

template<typename SOCK>
INLINE
TemplateUdpStream<SOCK>::TemplateUdpStream(unsigned short local_port, const char *local_addr)
{
	Init(local_port, local_addr);
}

template<typename SOCK>
INLINE
int TemplateUdpStream<SOCK>::Init(const InternetAddress &local_address)
{
	SOCKET handle;
	if ((handle = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET_HANDLE)
	{
		net_debug("TemplateUdpStream::Init() socket falied, error:%d\n", GetNetError());
		return -1;
	}

	if (bind(handle, (struct sockaddr*)local_address.GetAddress(), local_address.GetAddressSize()) == SOCKET_ERROR)
	{
		net_debug("TemplateUdpStream::Init() bind falied, error:%d\n", GetNetError());
		return -1;
	}

	return Attach(handle);
}

template<typename SOCK>
INLINE
int TemplateUdpStream<SOCK>::Init(unsigned short local_port, const char *local_addr)
{
	InternetAddress address(local_port, local_addr);
	return Init(address);
}

template<typename SOCK>
INLINE
int TemplateUdpStream<SOCK>::SendTo(const char *buf, int len, int flags, InternetAddress *peer_address)
{
	return sendto(GetHandle(), buf, len, flags, (const sockaddr *)peer_address->GetAddress(), peer_address->GetAddressSize());
}

template<typename SOCK>
INLINE
int TemplateUdpStream<SOCK>::RecvFrom(char *buf, int len, int flags, InternetAddress *peer_address)
{
	if (peer_address != 0)
	{
		int address_size = peer_address->GetAddressSize();
		int ret = recvfrom(GetHandle(), buf, len, flags, (sockaddr *)peer_address->GetAddress(), &address_size);
		peer_address->SetAddressSize(address_size);
		return ret;
	}
	else
	{
		return recvfrom(GetHandle(), buf, len, flags, 0, 0);
	}
}

}	// namespace net
}	// namespace vs

#endif	// __UDP_STREAM_H__
